package com.qing.annotation.singleton.module;

import com.qing.annotation.GenerateCode;
import com.squareup.javapoet.*;

import javax.annotation.processing.Filer;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import java.io.IOException;

/**
 *
 * 单例类注解实例
 *
 * @author qing <br/>
 * 2023/9/24
 */
public class SingletonAnnotatedClass implements GenerateCode {

    /**
     * 类元素
     */
    private final TypeElement mTypeElement;

    /**
     * 全类名
     */
    private final String mQualifiedSuperClassName;

    /**
     * ClassSimpleName
     */
    private final String mSimpleTypeName;

    /**
     * 自动生成的文件后缀 xxx_AutoSingleton
     */
    private static final String SUFFIX = "_AutoSingleton";


    public SingletonAnnotatedClass(TypeElement typeElement) {
        this.mTypeElement = typeElement;
        mQualifiedSuperClassName = typeElement.getQualifiedName().toString();
        mSimpleTypeName = typeElement.getSimpleName().toString();
    }

    public TypeElement getTypeElement() {
        return mTypeElement;
    }

    public String getQualifiedSuperClassName() {
        return mQualifiedSuperClassName;
    }

    public String getSimpleTypeName() {
        return mSimpleTypeName;
    }

    @Override
    public void generateCode(Elements elementUtils, Filer filer) throws IOException {
        String singletonClassName = mTypeElement.getSimpleName() + SUFFIX;
        PackageElement pkg = elementUtils.getPackageOf(mTypeElement);
        String packageName = pkg.isUnnamed() ? "" : pkg.getQualifiedName().toString();

        // 创建私有构造器
        MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder().addModifiers(Modifier.PRIVATE);

        // 实例字段
        FieldSpec.Builder instance = FieldSpec.builder(TypeName.get(mTypeElement.asType()), "sInstance", Modifier.VOLATILE, Modifier.STATIC, Modifier.PRIVATE);

        // 创建方法
        MethodSpec.Builder getInstance = MethodSpec.methodBuilder("getInstance")
                .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                .returns(TypeName.get(mTypeElement.asType()))
                .beginControlFlow("if (sInstance == null)")
                .beginControlFlow("synchronized ($L.class)", singletonClassName)
                .beginControlFlow("if (sInstance == null)")
                .addStatement("sInstance = new $L()", mQualifiedSuperClassName)
                .endControlFlow()
                .endControlFlow()
                .endControlFlow()
                .addStatement("return sInstance");

        TypeSpec typeSpec = TypeSpec.classBuilder(singletonClassName)
                .addModifiers(Modifier.PUBLIC)
                .addMethod(constructorBuilder.build())
                .addMethod(getInstance.build())
                .addField(instance.build()).build();

        JavaFile.builder(packageName, typeSpec).build().writeTo(filer);

    }
}
